// zoj3943
// 题意：给定n(<=10^5)个山，每个山初始高度hi(0<=hi<=10^5)。
//       定义山峰为不在两边且比相邻两座山都严格高的山。
//       现在有m(<=10^5)次地震，每次地震会影响[l, r]范围的山，
//       其中第i座山的高度会增加 A+(i-l)*B。
//       A(-10^5<=A<=10^5),B(1<=B<=10^5),l,r是一次地震的已知量。
//       要输出每次地震后山峰的个数。
//
// 题解：我们令Hi=h[i+1]-hi(1<=i<n), 我们只需要维护这个H序列，
//       一个山峰就是相邻的一对正负且正在前负在后。
//       然后我们观察到对于一段区间都加A对这段区间内的H是没有影响的，
//       而B的变化相当于对整段区间加B，然后区间端点出会发生变化。
//       并且区间内的数只可能单调的变化，即从负到零到正，虽然端点处可能
//       发生逆转，但是次数不会超过O(n+m)次。所以我们可以用线段树维护出
//       一个区间最大负数的值，如果这段加上B之后大于等于0, 就细分到叶子
//       节点更新山峰个数，因为这种变化可能会改变答案。
//       当然还要注意到山峰是严格大于，所以还要在线段树里维护出一端区间
//       零的个数，因为每次加的B都是正数，所以如果这个区间有0，那么也
//       需要细分到叶子节点，更新答案。
//
//       这样就ok啦。
//
// run: $exec < bfdiff.in
// opt: 0
// flag: -g
#include <cstdio>
#include <algorithm>

template <class T>
void scan(T & a)
{
	a = 0;
	bool flag = false;
	char ch = std::getchar();
	if (ch == '-')
		flag = true;
	else if (ch >= '0' && ch <= '9')
		a = ch - '0';

	while ((ch = std::getchar()) >= '0' && ch <= '9')
		a = a * 10 + ch - '0';
	if (flag) a = -a;
}

struct node
{
	long long nm; // negtive number maximum
	long long v;
	long long delta;
	int zero;
};

//int const maxn = 107;
int const maxn = 100007;
node tree[4 * maxn];
long long h[maxn];
int n, m, ans;

void init()
{
	ans = 0;
	for (int i = 2; i < n; i++)
		if (h[i] > h[i - 1] && h[i] > h[i + 1]) ans++;
}

void push_down(int id)
{
	tree[id * 2].delta += tree[id].delta;
	tree[id * 2 + 1].delta += tree[id].delta;
	tree[id * 2].nm += tree[id].delta;
	tree[id * 2 + 1].nm += tree[id].delta;
	tree[id].delta = 0;
}

void push_up(int id)
{
	if (tree[id * 2].nm < 0 && tree[id * 2 + 1].nm < 0)
		tree[id].nm = std::max(tree[id * 2].nm, tree[id * 2 + 1].nm);
	else if (tree[id * 2].nm < 0)
		tree[id].nm = tree[id * 2].nm;
	else if (tree[id * 2 + 1].nm < 0)
		tree[id].nm = tree[id * 2 + 1].nm;
	else
		tree[id].nm = 0;
	tree[id].zero = tree[id * 2].zero + tree[id * 2 + 1].zero;
}

void build(int id, int l, int r)
{
	tree[id].delta = 0;
	if (l == r) {
		tree[id].v = h[l];
		tree[id].nm = h[l] < 0 ? h[l] : 0;
		tree[id].zero = h[l] == 0;
		return;
	}
	int mid = (l + r) / 2;
	build(id * 2, l, mid);
	build(id * 2 + 1, mid + 1, r);
	push_up(id);
}

long long update_one(int id, int l, int r, int p, long long d)
{
	if (l == r) {
		tree[id].v += tree[id].delta + d;
		tree[id].delta = 0;
		tree[id].nm = tree[id].v;
		tree[id].zero = tree[id].v == 0;
		return tree[id].v;
	}
	push_down(id);
	int mid = (l + r) / 2, t;
	if (p <= mid) t = update_one(id * 2, l, mid, p, d);
	else t = update_one(id * 2 + 1, mid + 1, r, p, d);
	push_up(id);
	return t;
}

long long query(int id, int l, int r, int p, int sum = 0)
{
	if (l == r) return sum + tree[id].delta + tree[id].v;
	int mid = (l + r) / 2;
	if (p <= mid) return query(id * 2, l, mid, p, sum + tree[id].delta);
	else return query(id * 2 + 1, mid + 1, r, p, sum + tree[id].delta);
}

void change_to_ans(int p, long long before)
{
//	std::cerr << ":: " << p << '\n';
	auto now = query(1, 1, n - 1, p);
	if (p > 1) {
		auto prev = query(1, 1, n - 1, p - 1);
		if (prev > 0) {
			if (before < 0 && now >= 0) ans--;
			else if (before >= 0 && now < 0) ans++;
		}
	}
	if (p < n - 1) {
		auto next = query(1, 1, n - 1, p + 1);
		if (next < 0) {
			if (before > 0 && now <= 0) ans--;
			else if (before <= 0 && now > 0) ans++;
		}
	}
}

bool neg_less(long long x, long long d) { return (x < 0 && -x <= d); }

void cover(int id, int l, int r, int tl, int tr, int d)
{
	if (tl > tr) return;
	if (tl <= l && r <= tr) {
		if (l == r) {
			auto before = tree[id].v + tree[id].delta;
			tree[id].v += tree[id].delta + d;
			tree[id].delta = 0;
			tree[id].nm = tree[id].v;
			tree[id].zero = tree[id].v == 0;
			change_to_ans(l, before);
		} else if (neg_less(tree[id].nm, d) || tree[id].zero) {
			int mid = (l + r) / 2;
			push_down(id);
			cover(id * 2, l, mid, tl, tr, d);
			cover(id * 2 + 1, mid + 1, r, tl, tr, d);
			push_up(id);
		} else {
			tree[id].delta += d;
			tree[id].nm += d;
		}
		return;
	}
	int mid = (l + r) / 2;
	push_down(id);
	if (tr <= mid) cover(id * 2, l, mid, tl, tr, d);
	else if (tl > mid) cover(id * 2 + 1, mid + 1, r, tl, tr, d);
	else {
		cover(id * 2, l, mid, tl, tr, d);
		cover(id * 2 + 1, mid + 1, r, tl, tr, d);
	}
	push_up(id);
}

int main()
{
	int T; scan(T);
	while (T--) {
		scan(n); scan(m);
		for (int i = 1; i <= n; i++) scan(h[i]);
		init();
		for (int i = 1; i < n; i++) h[i] = h[i + 1] - h[i];
		build(1, 1, n - 1);
		for (int i = 0; i < m; i++) {
			long long l, r, a, b;
			scan(l); scan(r); scan(a); scan(b);
			r--;
			if (l > 1) {
				auto before = query(1, 1, n - 1, l - 1);
				update_one(1, 1, n - 1, l - 1, a);
				change_to_ans(l - 1, before);
			}
			if (r < n - 1) {
				auto before = query(1, 1, n - 1, r + 1);
				auto t = -a - (r + 1 - l) * b;
				update_one(1, 1, n - 1, r + 1, t);
				change_to_ans(r + 1, before);
			}
			cover(1, 1, n - 1, l, r, b);
			printf("%d\n", ans);
		}
	}
}

